package cn.wawi.utils.gen;

import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import cn.wawi.utils.DateUtil;
import cn.wawi.utils.StringUtil;

public class GenEntityUtil {
	
	private String[] removedTableNamePrefixes = null;
	private String[] removedTableName = null;
	private String[] tableNames = null;
	private String baseModelPackageName=null;
	private String baseDaoPackageName=null;
	private String baseXmlPackageName=null;
    private Connection conn=null;

    /**
     * 
     */
    public GenEntityUtil(String ...tableNames){
    	this.conn=DBUtils.getConnection();
		if(tableNames==null||tableNames.length==0){
			this.tableNames=DBUtils.getTableNames(conn);
		}else{
			this.tableNames=tableNames;
		}
    }
	public static GenEntityUtil me(String ...tableNames){
		return new GenEntityUtil(tableNames);
	}
    /**
     * 自动生成代码
     */
	public  void generate(){
		try {
			DatabaseMetaData dbmd=conn.getMetaData();
			for(int i=0;i<tableNames.length;i++){
				String primarykey=null;
				if(!isRemoveTable(tableNames[i])){
					int j=0;
					ResultSet rs = dbmd.getColumns(null, null, tableNames[i], "%");
					ResultSet primaryKeys=dbmd.getPrimaryKeys(conn.getCatalog(), null, tableNames[i]);
					while(primaryKeys.next()){
						primarykey=primaryKeys.getString("COLUMN_NAME");
					}
					rs.last();
					int size = rs.getRow();
					String[] columns = new String[size];
					String[] colTypes = new String[size];
					String[] remarks = new String[size];
					rs.beforeFirst();
					while(rs.next()){
						columns[j] = rs.getString("COLUMN_NAME");
						colTypes[j] = rs.getString("TYPE_NAME");
						remarks[j]=rs.getString("REMARKS");
						if(remarks[j]==null||"".equals(remarks[j])){
							remarks[j]=columns[j];
						}
						j++;
					}
					String entity = parseEntity(columns,colTypes,remarks,tableNames[i],primarykey);
					String dao = parseDao(tableNames[i]);
					String xml=parseXml(columns,tableNames[i],primarykey);
					generateFile(tableNames[i],entity,dao,xml);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			DBUtils.close(conn);
		}
	}
	/**
	 * 是否不自动生成代码的表
	 */
	public boolean isRemoveTable(String tablename){
		boolean flag=false;
		for(String str: removedTableName){
			if(str!=null&&!str.equals("")&&StringUtil.containsIgnoreCase(tablename, str)){
				flag=true;
			}
		}
		return flag;
	}
	/**
	 * 获取实体名称
	 */
	public String getRealTableName(String tablename){
		String str=tablename;
		for(String s: removedTableNamePrefixes){
			str=str.replaceAll(s, "");
		}
		str=StringUtil.underlineToCamelhump(str);
		str=StringUtil.firstCharToUpperCase(str);
		return str;
	}
	/**
	 * 获取属性名称
	 */
	public String getColumnName(String column){
		String str=column;
		if(column.contains("_")){
			str=str.toLowerCase();
			str=StringUtil.underlineToCamelhump(str);
		}else if(StringUtil.isAllUpperCase(str)){
			str=str.toLowerCase();
		}
		return str;
	}
	/*
	 * 自动生成entity,dao,controller,mybatis文件
	 */
	public void generateFile(String tablename,String entity,String dao,String xml){
		try {
			File directory = new File(".");
			String entityPath=directory.getCanonicalPath()+"\\src\\"+this.baseModelPackageName.replace(".", "\\")+"\\";
			entityPath=entityPath.replace("\\", "/");
			String daoPath=directory.getCanonicalPath()+"\\src\\"+this.baseDaoPackageName.replace(".", "\\")+"\\";
			daoPath=daoPath.replace("\\", "/");
			String xmlPath=directory.getCanonicalPath()+"\\config\\"+this.baseXmlPackageName.replace(".", "\\")+"\\";
			xmlPath=xmlPath.replace("\\", "/");
			if(baseModelPackageName==null||baseModelPackageName.trim().equals("")){
				entity=null;
			}
			if(baseDaoPackageName==null||baseDaoPackageName.trim().equals("")){
				daoPath=null;
			}
			if(baseXmlPackageName==null||baseXmlPackageName.trim().equals("")){
				xml=null;
			}
			createFile(entityPath,getRealTableName(tablename)+".java",entity);
			createFile(daoPath,getRealTableName(tablename)+"Dao.java",dao);
			createFile(xmlPath,getRealTableName(tablename)+".xml",xml);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/*
	 * 生成entity,dao文件
	 */
	public void createFile(String path,String filename,String content){
		try {
			if(content!=null&&!content.trim().equals("")){
				File f=new File(path,filename);
				File file=new File(path);
				if(!file.exists()){
					file.mkdirs();
				}
				if(!f.exists()){
					f.createNewFile();
					FileWriter fw = new FileWriter(f);
					PrintWriter pw = new PrintWriter(fw);
					pw.println(content);
					pw.flush();
					pw.close();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 功能：生成实体类主体代码
	 */
	private String parseEntity(String[] columns, String[] colTypes,String[] remarks,String tablename,String primarykey) {
		StringBuffer sb = new StringBuffer();
		
		sb.append("package " + this.baseModelPackageName + ";\r\n");
		sb.append("\r\n");
		sb.append("import cn.wawi.common.annotation.TableField;\r\n");
		sb.append("import cn.wawi.common.annotation.TableName;\r\n");
		//注释部分
		sb.append("/**\r\n");
		sb.append(" * "+tablename+" 实体类\r\n");
		sb.append(" * "+DateUtil.getDate()+"\r\n");
		sb.append(" */\r\n");
		//实体部分
		sb.append("@TableName(value=\""+tablename+"\")\r\n");
		sb.append("public class " + getRealTableName(tablename) + "{\r\n\r\n");
		processAllAttrs(sb,columns,colTypes,remarks,primarykey);//属性
		processAllMethod(sb,columns,colTypes);//get set方法
		sb.append("}\r\n");
		return sb.toString();
	}
	/**
	 * 功能：生成Dao类主体代码
	 */
	public String parseDao(String tablename) {
		StringBuffer sb = new StringBuffer();
		
		sb.append("package " + this.baseDaoPackageName + ";\r\n");
		sb.append("\r\n");

		//实体部分
		sb.append("import cn.wawi.common.annotation.MybatisRepository;\r\n");
		sb.append("import cn.wawi.dao.BaseDao;\r\n");
		sb.append("import "+this.baseModelPackageName+"."+getRealTableName(tablename)+";\r\n");
		sb.append("\r\n@MybatisRepository\r\n");
		sb.append("public interface " + getRealTableName(tablename)+"Dao"+"<T extends "+getRealTableName(tablename)+">"+" extends BaseDao<"+getRealTableName(tablename)+">" + " {\r\n");
		sb.append("}\r\n");
		return sb.toString();
	}
	/**
	 * 功能：生成xml
	 */
	public String parseXml(String[] columns,String tablename,String primarykey) {
		StringBuffer sb = new StringBuffer();
		sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
		sb.append("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"  \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\r\n");
		sb.append("<mapper namespace=\""+this.baseDaoPackageName+"."+getRealTableName(tablename)+"Dao"+"\">\r\n");
		
		sb.append("\r\n\t<select id=\"findAll\" resultType=\""+this.baseModelPackageName+"."+getRealTableName(tablename)+"\" parameterType=\"java.util.Map\">\r\n");
		sb.append("\t\tselect * from "+tablename+"\r\n");
		sb.append("\t</select>");
		
		sb.append("\r\n\t<select id=\"findOne\" resultType=\""+this.baseModelPackageName+"."+getRealTableName(tablename)+"\" parameterType=\""+this.baseModelPackageName+"."+getRealTableName(tablename)+"\">\r\n");
		sb.append("\t\tselect * from "+tablename+" where "+primarykey+"=#{"+getColumnName(primarykey)+"}");
		sb.append("\r\n\t</select>"); 
		
		sb.append("\r\n\t<insert id=\"saveOne\" parameterType=\""+this.baseModelPackageName+"."+getRealTableName(tablename)+"\">\r\n");
		sb.append("\t\t"+buildInsert(columns,tablename,primarykey)+"\r\n");
		sb.append("\t</insert>\r\n");
		
		sb.append("\r\n\t<update id=\"updateOne\" parameterType=\""+this.baseModelPackageName+"."+getRealTableName(tablename)+"\">\r\n");
		sb.append("\t\t"+buildUpdate(columns,tablename,primarykey)+"\r\n");
		sb.append("\t</update>\r\n");
		
		sb.append("\t<delete id=\"deleteOne\" parameterType=\"string\">\r\n");
		sb.append("\t\t delete from "+tablename+" where "+primarykey+"=#{id}\r\n");
		sb.append("\t</delete>\r\n");
		
		sb.append("\r\n\t<update id=\"updateBatch\">\r\n");
		sb.append("\t\tupdate "+tablename+" set status=0 where id in <foreach collection=\"array\" item=\"item\" open=\"(\" close=\")\" separator=\",\">#{item}</foreach>");
		sb.append("\r\n\t</update>");
		
		sb.append("\r\n\t<delete id=\"deleteBatch\">\r\n");
		sb.append("\t\tdelete from "+tablename+" where id in <foreach collection=\"array\" item=\"item\" open=\"(\" close=\")\" separator=\",\">#{item}</foreach>");
		sb.append("\r\n\t</delete>");
		
		sb.append("\r\n</mapper>");
		return sb.toString();
	}
	/**
	 * 功能：生成所有方法
	 * @param sb
	 */
	private void processAllMethod(StringBuffer sb,String[] columns,String[] colTypes) {
		for (int i = 0; i < columns.length; i++) {
			String column=getColumnName(columns[i]);
			if(!("createTime".equals(column)||"updateTime".equals(column))){
			    sb.append("\tpublic void set" + StringUtil.firstCharToUpperCase(column) + "(" + sqlType2JavaType(colTypes[i]) + " " + 
						column + "){\r\n");
				if("String".equals(sqlType2JavaType(colTypes[i]))){
					sb.append("\t\tthis." + column + "=" + column + "==null?null:"+column+".trim();\r\n");
				}else{
					sb.append("\t\tthis." + column + "=" + column + ";\r\n");	
				}
				sb.append("\t}\r\n");
				sb.append("\tpublic " + sqlType2JavaType(colTypes[i]) + " get" + StringUtil.firstCharToUpperCase(column) + "(){\r\n");
				sb.append("\t\treturn " + column + ";\r\n");
				sb.append("\t}\r\n");
			}
		}
	}
	/**
	 * 功能：生成所有属性
	 * @param sb
	 */
	private void processAllAttrs(StringBuffer sb,String[] columns,String[] colTypes,String[] remarks,String primarykey) {
		boolean flag=true;
		for (int i = 0; i < columns.length; i++) {
			String type=sqlType2JavaType(colTypes[i]);
			if(primarykey.equals(columns[i])){
				sb.append("\t/**\r\n");
				sb.append("\t *注释: "+remarks[i]+"\r\n");
				sb.append("\t */\r\n");
				sb.append("\t@TableField(value=\""+columns[i]+"\",isPrimaryKey=true)\r\n");
				sb.append("\tprivate " + type + " " + getColumnName(columns[i]) + ";\r\n");
			}else{
				sb.append("\t/**\r\n");
				sb.append("\t *注释: "+remarks[i]+"\r\n");
				sb.append("\t */\r\n");
				if("java.util.Date".equals(type)){
					sb.append("\t@TableField(value=\""+columns[i]+"\")\r\n");
					sb.append("\t@JsonFormat(pattern=\"yyyy-MM-dd hh:mm:ss\")\r\n");
					if(flag){
						sb.insert(this.baseModelPackageName.length()+10, "\r\nimport com.fasterxml.jackson.annotation.JsonFormat;");
						flag=false;
					}
					sb.append("\tprivate " + type + " " + getColumnName(columns[i]) + "=new java.util.Date();\r\n"); 
				}else{
					sb.append("\t@TableField(value=\""+columns[i]+"\")\r\n");
					sb.append("\tprivate " + type + " " + getColumnName(columns[i]) + ";\r\n");
				}
			}
		}
	}
	/**
	 * 功能：获得列的数据类型
	 * @param sqlType
	 * @return
	 */
	private String sqlType2JavaType(String sqlType) {
		if(sqlType.equalsIgnoreCase("bit")){
			return "Boolean";
		}else if(sqlType.equalsIgnoreCase("tinyint")){
			return "Integer";
		}else if(sqlType.equalsIgnoreCase("smallint")){
			return "Short";
		}else if(sqlType.equalsIgnoreCase("int")){
			return "Integer";
		}else if(sqlType.equalsIgnoreCase("bigint")){
			return "Long";
		}else if(sqlType.equalsIgnoreCase("float")){
			return "Float";
		}else if(sqlType.equalsIgnoreCase("decimal") || sqlType.equalsIgnoreCase("numeric") 
				|| sqlType.equalsIgnoreCase("real") || sqlType.equalsIgnoreCase("money") 
				|| sqlType.equalsIgnoreCase("smallmoney")){
			return "Double";
		}else if(sqlType.equalsIgnoreCase("varchar") || sqlType.equalsIgnoreCase("char") 
				|| sqlType.equalsIgnoreCase("nvarchar") || sqlType.equalsIgnoreCase("nchar") 
				|| sqlType.equalsIgnoreCase("text")){
			return "String";
		}else if(sqlType.equalsIgnoreCase("datetime")||sqlType.equalsIgnoreCase("timestamp")){
			return "java.util.Date";
		}else if(sqlType.equalsIgnoreCase("image")){
			return "java.sql.Blod";
		}
		
		return null;
	}
	public GenEntityUtil setRemovedTableNamePrefixes(String ...removedTableNamePrefixes) {
		this.removedTableNamePrefixes = removedTableNamePrefixes;
		return this;
	}
	public GenEntityUtil setTableNames(String ...tableNames) {
		this.tableNames = tableNames;
		return this;
	}
	public GenEntityUtil setBasePackageName(String baseModelPackageName,String baseDaoPackageName,String baseXmlPackageName) {
		this.baseModelPackageName = baseModelPackageName;
		this.baseDaoPackageName=baseDaoPackageName;
		this.baseXmlPackageName=baseXmlPackageName;
		return this;
	}
	
	public GenEntityUtil setRemovedTableName(String ...removedTableName) {
		this.removedTableName = removedTableName;
		return this;
	}
    public String buildInsert(String[] columns, String tablename, String primarykey){
    	String sql="insert into "+tablename;
    	String strs="(";
    	String values=" values(";
    	for(String column: columns){
    		if(!column.equals(primarykey)){
        		strs+=column+",";
        		values+="#{"+getColumnName(column)+"},";
    		}
    	}
    	sql+=strs.substring(0, strs.lastIndexOf(","))+") "+values.substring(0, values.lastIndexOf(","))+")";
    	return sql;
    }
    public String buildUpdate(String[] columns, String tablename, String primarykey){
    	String sql="update "+tablename+" \r\n";
    	String set="\t\t<set>";
    	for(String column: columns){
    		if(!column.equals(primarykey))
    		 set+="\r\n\t\t <if test=\""+getColumnName(column)+" !=null\">"+column+"=#{"+getColumnName(column)+"},</if>";
    	}
    	set=set+"\r\n\t\t</set> ";
    	sql=sql+set+" where "+primarykey+"=#{"+getColumnName(primarykey)+"}";
    	return sql;
    }
}
